const fs = require('fs');
const path = require('path');
const _ = require('lodash');

/**
 * 读取 目录
 * @param dir
 * @param options
 * eg : {
 *   excludes: [/node_modules/, isJsFileFn ], // 文件过滤条件组,支持 RegExp, Function, String,满足其一即排除
 *   recursion: true, // 是否递归遍历
 *   onlyFile : true, // 只返回文件,过滤文件夹
 * }
 * @param callback
 * @returns {*[]|*|boolean|string[]}
 */
function readDir(dir, options, callback) {
  if (!path.isAbsolute(dir)) {
    dir = path.resolve(dir);
  }
  if (!fs.existsSync(dir)) {
    return false;
  }
  if (_.isNil(options) || !_.isObject(options)) {
    options = {
      async: false,
      recursion: true,
    }
  }
  let { recursion = false } =  options;
  if (true === _.get(options, 'async')) {
    fs.readdir(dir, options, (data) => {
      if (_.isFunction(callback)) {
        return callback(result);
      }

    });
    return true;
  }
  let result = fs.readdirSync(dir, options);
  if (_.isNil(result) || 0 === result.length) {
    return [];
  }
  if (true === recursion) {
    let opt = options;
    opt.basePath = dir;
    return readDirRecursion(result, opt, callback)
  }
  if (_.isFunction(callback)) {
    return callback(result);
  }
  return result;
}

/**
 * 递归读取文件目录
 * @param files
 * @param options
 * {
 *   bashPath : __dirname, // 根目录
 *   excludes: [/node_modules/, isJsFileFn ], // 文件过滤条件组 : 支持 RegExp, Function, String, 满足其一即排除
 *   recursion: true, // 是否递归遍历
 *   onlyFile : true, // 只返回文件,过滤文件夹
 * }
 * @param callback
 * @returns {[]|*[]|*}
 */
function readDirRecursion(files, options, callback) {
  if (_.isEmpty(files) || _.isNil(files)) {
    return [];
  }
  if (_.isString(files) && '' !== files) {
    files = [files]
  }
  if (!_.isArray(files) || 0 === files.length) {
    return []
  }
  if (_.isUndefined(options) || !_.isObject(options)) {
    options = {
      recursion: true,
      basePath: __dirname,
    }
  }
  let arr = [];
  let {recursion = true} = options;
  files.forEach((file, _index) => {
    var opts = {};
    let base = _.get(options, 'basePath') || __dirname;
    if (!path.isAbsolute(file)) {
      file = path.join(base, file)
    }
    if (!fileExits(file)) {
      return;
    }
    let {excludes = []} = options;
    // 排除
    if (Excludes(file, excludes) || ['.', '..'].includes(file)) {
      return;
    }
    let isDirPath = isDir(file);
    if(!isDirPath){
       arr.push(file);
    }
    else if(true !== _.get(options,'onlyFile')){
      arr.push(file);
    }
    if (isDirPath && true === recursion) {
      opts = _.extend({}, options);
      opts.basePath = file;
      let subs = fs.readdirSync(file, opts);
      if (!_.isArray(subs) || 0 === subs.length) {
        return;
      }
      let sub = readDirRecursion(subs, opts);
      if (0 !== sub.length) {
        arr.push(...sub)
      }
      delete opts
    }
  });

  if (_.isFunction(callback)) {
    return callback(arr)
  }
  return arr
}

/**
 * 排除
 * @param file
 * @param exclude
 * @returns {*|boolean}
 */
function Excludes(file, exclude) {
  if (_.isNil(exclude) || false === exclude) {
    return false
  }
  // 多条件排除
  if (_.isArray(exclude)) {
    if (_.isEmpty(exclude)) {
      return false
    }
    let isOk = false;
    _.each(exclude, (val, _i) => {
      if (isOk) {
        return;
      }
      if (_.isRegExp(val) && val.test(file)) {
        isOk = true;
        return;
      }
      if (_.isString(val) && val === file) {
        isOk = true;
        return;
      }
      if (_.isFunction(val) && val(file)) {
        isOk = true;
      }
    });
    return isOk
  }
  if (_.isFunction(exclude)) {
    return exclude(file);
  }
  return _.isRegExp(exclude) && exclude.test(file)
}

/**
 * 是否文件夹
 * @param file
 * @returns {boolean}
 */
function isDir(file) {
  let state = fs.statSync(file);
  return state.isDirectory()
}

/**
 * 获取上级文件目录
 * @param file
 * @param level
 * @returns {string|*}
 */
function dirname(file, level) {
  if (_.isNil(level) || !_.isNumber(level)) {
    level = 1;
  }
  if (level <= 1) {
    return path.dirname(file)
  }
  while (level > 0) {
    file = path.dirname(file);
    level--;
  }
  if (!path.isAbsolute(file)) {
    return path.resolve(file)
  }
  return file
}

/**
 * 文件是否存在
 * @param file
 * @returns {boolean}
 */
function fileExits(file) {
  if (!_.isString(file) || _.isNil(file) || '' === file) {
    return false
  }
  return fs.existsSync(file)
}

let options = {
  excludes: [/node_modules/],
  recursion: true,
};

// eg :
// let files = readDir(dirname('./', 2), options,(files)=>{
//     files.forEach((file,i)=>{
//       console.log(i + " => " + file)
//     })
// });

module.exports = {
  readDir,
  isDir,
  fileExits,
  dirname,
  readDirRecursion,
  Excludes,
};